/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package estg.dae.projecto.bank.controllers;

import estg.dae.projecto.bank.OperationType;
import estg.dae.projecto.bank.impl.AccountInfoTO;
import estg.dae.projecto.bank.impl.AccountMovementTO;
import estg.dae.projecto.bank.impl.BankTO;
import estg.dae.projecto.bank.impl.ElectronicOperationTO;
import estg.dae.projecto.bank.model.Account;  
import estg.dae.projecto.bank.model.AccountMovement;
import estg.dae.projecto.bank.model.BankSettings;
import estg.dae.projecto.bank.model.Client;
import estg.dae.projecto.bank.model.ElectronicTransfer;
import estg.dae.projecto.bank.utils.BrokerServiceLocator;
import estg.dae.projecto.broker.controllers.IBrokerControllerRemote;
import estg.dae.projecto.exceptions.OfflinetransferFailedException;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.jms.Session;

/**
 *
 * @author Marco
 */
@Stateless
@Remote(IBankControllerRemote.class)
public class BankSessionBean implements BankSessionLocal, IBankControllerRemote {
    @EJB
    private AccountControllerLocal accountService;
    @EJB
    private ClientControllerLocal clientService;

    // <editor-fold defaultstate="collapsed" desc="Remote methods implementation">
    //Remote bean implementation
    public boolean validateNib(String nib) {
        return accountService.existsNib(nib);
    }

    public void executeOnlineOperation(ElectronicOperationTO operation) throws OfflinetransferFailedException {
        accountService.executeOnlineOperation(operation);
    }

    public void confirmOnlineOperation(ElectronicOperationTO operation) throws OfflinetransferFailedException {
        accountService.confirmOnlineOperation(operation);
    }
    public void failedOnlineOperation(ElectronicOperationTO operation, String message) {
        accountService.failedOnlineOperation(operation, message);
    }
    public void setSyncronizationTime(Date time) {

        return;
    }

    public AccountInfoTO getAccountInfo(String nib) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public AccountInfoTO getAccountInfoFromCard(String cardNumber) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public double getAccountBalance(String nib) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public Collection<AccountMovementTO> getAccountMovement(String nib) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public Collection<AccountMovementTO> getAccountMovementFromCard(String cardNumber) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Local methods implementation">
    public boolean existsAccountByNib(String nib) {
        return accountService.existsNib(nib);
    }
    public boolean existsAccountByNumber(long number) {
        return accountService.existsNumber(number);
    }

    public Account getAccountByNib(String nib) {
        return accountService.getByNib(nib);
    }
    public Account getAccountByNumber(long number) {
        return accountService.getByNumber(number);
    }
    public Account getAccountById(long id) {
        return accountService.get(id);
    }
    public Account createAccount(Client client, int agencyCode, double overBalance) {
        Account account = accountService.createAccount(client, agencyCode, overBalance);
        return account;
    }
    public void updateAccount(Account account) {
        accountService.update(account);
    }
    public Collection<AccountMovement> getAccountMovements(Account account, int movs) {
        return accountService.getMovements(account.getId(), 15);
    }

    public AccountMovement doWithdraw(String originAccountRef, double value) throws Exception {
        return accountService.doWithdraw(originAccountRef, value);
    }
    public AccountMovement doTransfer(String originAccountRef, String destinAccountRef, double value) throws Exception {
        return accountService.doTransfer(originAccountRef, destinAccountRef, value);
    }
    public AccountMovement doMoneyDeposit(String destinAccountRef, double value) throws Exception {
        return accountService.doMoneyDeposit(destinAccountRef, value);
    }
    public AccountMovement doCheckDeposit(String originAccountRef, String destinAccountRef, double value) throws Exception {
        return accountService.doCheckDeposit(originAccountRef, destinAccountRef, value);
    }

    public Collection<ElectronicTransfer> getOfflineTransfers() {
        return accountService.getofflineTransfers();
    }

    public void sendOfflineTransfer(ElectronicOperationTO electronicOperationTO) {

        try {
            QueueConnectionFactory queueFactory = BrokerServiceLocator.getRemoteQueueConnectionFactory();
            Queue messageQueue = BrokerServiceLocator.getRemoteQueue();

            Connection connection = queueFactory.createConnection();
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

                ObjectMessage objMessage = session.createObjectMessage(electronicOperationTO);
                MessageProducer messageProducer = session.createProducer(messageQueue);
                messageProducer.send(objMessage);
                session.close();
                if (connection != null) {
                    connection.close();
                }
        } catch (JMSException ex) {
            Logger.getLogger(ex.getMessage()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(BankSessionBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public Client getClientById(int clientId) {
        return clientService.get(clientId);
    }

    public void createClient(Client client, int agencyCode) {
        clientService.save(client, agencyCode);
    }

    public void updateClient(Client client) {
        clientService.update(client);
    }

    public Collection<Client> getAllClients() {
        return clientService.getAll();
    }


    // </editor-fold>
    
    @PostConstruct
    private void initializeSessionBean() {
        try {
            IBrokerControllerRemote brokerService = BrokerServiceLocator.getBrokerService();
            BankSettings bankSettings = BankSettings.getInstance();
            if (brokerService != null && !brokerService.isBankRegistered(bankSettings.getCode())) {
                BankTO bank = new BankTO(bankSettings);
                brokerService.registerBank(bank);
            }

            // TEST MICKAEL
            Collection<ElectronicTransfer> transfers = getOfflineTransfers();

        for(ElectronicTransfer transfer : transfers) {
            sendOfflineTransfer(new ElectronicOperationTO(transfer));
        }
        } catch (Exception ex) {
            Logger.getLogger(BankSessionBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @PreDestroy
    private void finalizeSessionBean() {
        try {
            IBrokerControllerRemote brokerService = BrokerServiceLocator.getBrokerService();
            BankSettings bankSettings = BankSettings.getInstance();
            if (brokerService != null && brokerService.isBankRegistered(bankSettings.getCode())) {
                BankTO bank = new BankTO(bankSettings);
                brokerService.unregisterBank(bank.getCode());
            }
        } catch (Exception ex) {
            Logger.getLogger(BankSessionBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}
